浅谈 MVVM 和 Vue
使用 jQuery 和使用其他框架的区别
jQuery 实现 todo-list
1 | <div> |
Vue 实现 todo-list
1 | <div id="app"> |
jQuery 和 Vue 的区别
- 数据和视图的分离,解耦(开放封闭原则)
在 jQuery 的例子中,li
元素通过 DOM
操作添加到 ul
元素中,逻辑和视图混在了一起,数据和视图也就没有分离。不符合封闭开放原则。
在 Vue 的例子中,数据和视图分离。
- 以数据驱动视图
在 jQuery 的例子中,直接通过 DOM
操作修改视图。
在 Vue 的例子中,通过修改数据来改变视图。如何改变视图,如何渲染,我们并不关心,我们只关心数据变化,因为 DOM 操作已经被封装。
对 MVVM 的理解
MVC
- Model 模型,数据
- View 视图,模板
- Controller 控制器,逻辑处理
MVVM
- Model 模型,数据
- View 视图,模板
- ViewModel 连接视图和模型的桥梁
MVVM 是 MVC 的微创新
MVVM 的三大要素
数据响应:Vue 如何监听到 data 的每个属性变化
通过 Object.defineProperty
监听对象的获取和变化
1 | var obj = { |
上面的例子中,通过对象字面量的形式无法监听对象的获取和变化。
1 | var obj = {} |
上面的例子中,通过 Object.defineProperty
可以监听到对象的获取和变化。
1 | var vm = {} |
上面的代码模拟 Vue 的内部实现:利用 Object.defineProperty
监听到对象的获取和变化以及模拟 data 属性代理到 Vue 实例 vm
模板解析: vue 的模板如何被解析,指令如何处理
- 模板是什么
- 模板的本质是字符串。
- 有逻辑。 如
v-if
v-for
等 - 与 html 格式很像,但是有很大区别
- 最终要转换为 html 来显示
- 模板最终必须转换成 JS 代码,因为:
- 有逻辑(
v-if
v-for
)必须用 JS 才能实现(图灵完备)。 - 转换为 html 渲染页面,必须用 JS 才能实现
- 模板最重要转换成一个 JS 函数(render 函数)
1
2
3
4
5
6
7
8
9<div id="app">
<div>
<input v-model="title">
<button :click="add">submit</button>
</div>
<ul id="ul-list">
<li v-for="item in list">{{item}}</li>
</ul>
</div>
- 有逻辑(
render 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41<div id="app">
<p>{{price}}</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
price: 100
}
})
// 以下是手写的 ppt 中的 render 函数
function render() {
// this 就是 vm
with(this) {
return _c(
'div',
{
attrs: {'id': 'app'}
},
[
_c('p', [_v(_s(price))])
]
)
}
}
// 上面的 render 函数相当于下面的 render 函数
function render1() {
return vm._c(
'div',
{
attrs: {'id': 'app'}
},
[
vm._c('p', [vm._v(vm._s(vm.price))])
]
)
}
</script>render 函数 与 vdom
1
2
3
4
5
6
7
8
9
10
11
12
13
14vm._update(vnode) {
const prevVnode = vm.vnode
vm.vnode = vnode
if (!prevVnode) {
vm.$el = vm.__patch__(vm.$el, vnode)
} else {
vm.$el = vm.__patch__(prevVnode, vnode)
}
}
function updateComponent () {
// vm._render 即 render 函数,返回 vnode
vm._update(vm._render())
}updateComponent 实现了 vdom 的 patch
- 页面首次渲染执行了 updateComponent
- data 中每次修改属性都会执行 updateComponent
渲染: vue 的模板如何被渲染成 html ? 以及渲染过程
- 解析模板成 render 函数
- 模板中的所有信息都被 render 函数包含
- 模板用到的 data 中的属性,都变成了 JS 变量
- 模板中的
v-model
、v-for
、v-on
都变成了 JS 逻辑 - render 函数返回 vnode
- 数据响应开始监听
Object.defineProperty
- 将 data 的属性代理到 Vue 实例
- 首次渲染,显示页面,且绑定依赖。
- 初次渲染,执行 updateComponent ,执行 vm._render()
- 执行 render 函数,会访问到被 Vue 实例代理的 data 的属性
- 会被数据响应的
Object.defineProperty
的 get 方法监听到(只监听需要用的的属性,没有用到的不关心,避免不必要的重复渲染) - 执行 updateComponent,会走 vdom 的 patch 方法
- patch 将 vnode 渲染成 DOM ,初次渲染完成
- data 属性变化,触发 rerender
- 修改属性,会被数据响应的
Object.defineProperty
的 set 方法监听到 - set 方法中执行 updateComponent
- updateComponent 重新执行 vm.render
- 生成 vnode 和 prevVnode ,通过 patch 进行比较
- 渲染到 html